package redis

import (
	"context"
	"fmt"
	"manager/store/redis/base"
	"sync"
	"time"

	Redis "github.com/gomodule/redigo/redis"
)

type CacheType string

// CacheType 缓存类型
const (
	CacheKey   CacheType = "key"   // 普通key
	CacheValue CacheType = "value" // 普通value
	CacheList  CacheType = "list"  // 列表
	CacheHash  CacheType = "hSet"  // 哈希
	CacheZSet  CacheType = "zSet"  // z set
	CacheBit   CacheType = "bit"   // bit
)

var (
	cacheMap = map[CacheType]string{
		CacheKey:   "key",
		CacheValue: "value",
		CacheList:  "list",
		CacheHash:  "hSet",
		CacheZSet:  "zSet",
		CacheBit:   "bit",
	}
	redisCache *Client
	_once      sync.Once
)

// IRedisHash 哈希操作
type IRedisHash interface {
	// AddHash 添加值
	AddHash(ctx context.Context, hashName, key string, value interface{}) (err error)
	// DelHash 删除值
	DelHash(ctx context.Context, hashName, key string) (err error)
	// GetHash 获取hash值
	GetHash(ctx context.Context, hashName, key string, out interface{}) (err error)
	// HMGet 获取hash值
	HMGet(ctx context.Context, hashName string, keys []string) (values map[string]string, err error)
	// HMSet 设置值
	HMSet(ctx context.Context, hashName string, fieldValue map[interface{}]interface{}) (err error)
	// HGetAll 获取所有
	HGetAll(ctx context.Context, hashName string) (values map[string]string, err error)
	// HDelAll 删除所有
	HDelAll(ctx context.Context, hashName string) (bSuccess bool)
	// Hincrby 自增
	Hincrby(ctx context.Context, hashName string, key string, increment interface{}) (int64, error)
}

// IZSet zSet
type IZSet interface {
	ZAdd(ctx context.Context, key string, score int64, member string) (value int64, err error)
	ZRem(ctx context.Context, key, member string) (value int64, err error)
	ZRange(ctx context.Context, key string, start, stop int64) (valSlice []string, err error)
	ZRevRange(ctx context.Context, key string, start, stop int64) (valSlice []string, err error)
	ZBatchAdd(ctx context.Context, key string, scoreMemberPairs []string) (value int64, err error)
}

type IRedis interface {
	// AddValue 添加值
	AddValue(ctx context.Context, groupName, key string, value interface{}) (err error)
	// AddValueWithExpireTime 添加值待过期时间
	AddValueWithExpireTime(ctx context.Context, groupName, key string, value interface{}, expiredTime time.Duration) (err error)
	// GetValue 获取值
	GetValue(ctx context.Context, groupName, key string, out interface{}) (err error)
	// DelValue 删除值
	DelValue(ctx context.Context, groupName, key string) (err error)
	// ValueExist 是否存在值
	ValueExist(ctx context.Context, groupName, key string) bool
}

// IRedisList 列表操作
type IRedisList interface {
	// AddList 添加列表
	AddList(ctx context.Context, listName string, value string) bool
	// BatchAddList 添加列表
	BatchAddList(ctx context.Context, listName string, value ...string) bool
	// DelList 删除列表
	DelList(ctx context.Context, listName string, value string) bool
	// PopFormList 去除列表中的第一个元素
	PopFormList(ctx context.Context, listName string) (value string)
	// BPopFormList 获取列表中的第一个数据
	BPopFormList(ctx context.Context, listName string) (value string)
	// GetFirstFormList 获取列表中第一个元素
	GetFirstFormList(ctx context.Context, listName string) (value string)
	// GetItemFromList 获取元素
	GetItemFromList(ctx context.Context, listName string, item string) (value string)
	// GetRangeFromQueue 获取列表
	GetRangeFromQueue(ctx context.Context, listName string, count int64) []string
	// LenList 列表长度
	LenList(ctx context.Context, listName string) (len int64, err error)
	// AddListToTail 头插
	AddListToTail(ctx context.Context, listName string, value string) (err error)
	// ListRange 列表数据
	ListRange(ctx context.Context, listName string, from, to int64) []string
}

// IBit 位操作
type IBit interface {
	// GetBit 获取bit
	GetBit(ctx context.Context, key string, offset int) (value int, err error)
	// SetBit 设置bit
	SetBit(ctx context.Context, key string, offset, value int) (err error)
	// SetBitWithExpireTime 设置bit
	SetBitWithExpireTime(ctx context.Context, key string, offset, value int, expiredTime time.Duration) (err error)
	// MGetBit 批量获取
	MGetBit(ctx context.Context, key string, offsets []int) (value []int, err error)
}

type IKey interface {
	// BatchAdd 批量添加
	BatchAdd(ctx context.Context, filed map[string]string) (err error)
	// GetValByKey 依据KEY获取REDIS数据
	GetValByKey(ctx context.Context, key string) string
}

type IBase interface {
	// BatchDel 批量删除 完整key
	BatchDel(ctx context.Context, keys []string) (count int, err error)
	// DeletedRedisItem 删除redis item 完整key
	DeletedRedisItem(ctx context.Context, cacheType CacheType, key string) bool
	// Expire 设置过期时间 完整key
	Expire(ctx context.Context, cacheType CacheType, key string, seconds time.Duration) (err error)
	// ExistsKey 是否存在
	ExistsKey(ctx context.Context, cacheType CacheType, groupName, key string) bool
	// MatchDel 模糊删除
	MatchDel(cacheType CacheType, prefixKey string) (err error)
	MatchCount(cacheType CacheType, prefixKey string) (count int64, err error)
	GetRedisPool() *Redis.Pool
	// GetPrefixName prefix
	GetPrefixName(cacheType CacheType) string
}

var operator *base.RedisOperator

func InitClient(conf *base.Options) *Client {
	operator = base.NewRedisOperator(base.NewRedisClient(conf))
	return &Client{}
}

// Client 基础缓存
type Client struct {
}

func (r *Client) Close() error {
	return r.GetRedisPool().Close()
}

// AddHash 添加值
func (r *Client) AddHash(ctx context.Context, hashName, key string, value interface{}) (err error) {
	hashName = fmt.Sprintf("%v:%v", CacheHash, hashName)
	return operator.AddHash(ctx, hashName, key, value)
}

// DelHash 删除值
func (r *Client) DelHash(ctx context.Context, hashName, key string) (err error) {
	hashName = fmt.Sprintf("%v:%v", CacheHash, hashName)
	return operator.DelHash(ctx, hashName, key)
}

// GetHash 获取hash值
func (r *Client) GetHash(ctx context.Context, hashName, key string, out interface{}) (err error) {
	hashName = fmt.Sprintf("%v:%v", CacheHash, hashName)
	return operator.GetHash(ctx, hashName, key, out)
}

// HMGet 获取hash值
func (r *Client) HMGet(ctx context.Context, hashName string, keys []string) (values map[string]string, err error) {
	hashName = fmt.Sprintf("%v:%v", CacheHash, hashName)
	return operator.HMGet(ctx, hashName, keys)
}

// HGetAll 获取所有
func (r *Client) HGetAll(ctx context.Context, hashName string) (values map[string]string, err error) {
	hashName = fmt.Sprintf("%v:%v", CacheHash, hashName)
	return operator.HGetAll(ctx, hashName)
}

// HDelAll 删除所有
func (r *Client) HDelAll(ctx context.Context, hashName string) (bSuccess bool) {
	return r.DeletedRedisItem(ctx, CacheHash, hashName)
}

// Hincrby 设置过期时间
func (r *Client) Hincrby(ctx context.Context, hashName string, key string, increment interface{}) (int64, error) {
	hashName = fmt.Sprintf("%v:%v", CacheHash, hashName)
	return operator.Hincrby(ctx, hashName, key, increment)
}

// HMSet 设置值
func (r *Client) HMSet(ctx context.Context, hashName string, fieldValue map[interface{}]interface{}) (err error) {
	hashName = fmt.Sprintf("%v:%v", CacheHash, hashName)
	return operator.HMSet(ctx, hashName, fieldValue)
}

func (r *Client) ZAdd(ctx context.Context, key string, score int64, member string) (value int64, err error) {
	key = fmt.Sprintf("%v:%v", CacheZSet, key)
	return operator.ZAdd(ctx, key, score, member)
}

func (r *Client) ZRem(ctx context.Context, key, member string) (value int64, err error) {
	key = fmt.Sprintf("%v:%v", CacheZSet, key)
	return operator.ZRem(ctx, key, member)
}

func (r *Client) ZRange(ctx context.Context, key string, start, stop int64) (valSlice []string, err error) {
	key = fmt.Sprintf("%v:%v", CacheZSet, key)
	return operator.ZRange(ctx, key, start, stop)
}

func (r *Client) ZBatchAdd(ctx context.Context, key string, scoreMemberPairs []string) (value int64, err error) {
	key = fmt.Sprintf("%v:%v", CacheZSet, key)
	return operator.ZBatchAdd(ctx, key, scoreMemberPairs)
}

// AddValue 添加值
func (r *Client) AddValue(ctx context.Context, groupName, key string, value interface{}) (err error) {
	groupName = fmt.Sprintf("%v:%v", CacheValue, groupName)
	return operator.AddValue(ctx, groupName, key, value)
}

// AddValueWithExpireTime 添加值
func (r *Client) AddValueWithExpireTime(ctx context.Context, groupName, key string, value interface{}, expiredTime time.Duration) (err error) {
	groupName = fmt.Sprintf("%v:%v", CacheValue, groupName)

	expire := expiredTime / time.Second
	return operator.AddValueWithExpireTime(ctx, groupName, key, value, int64(expire))
}

func (r *Client) ValueExist(ctx context.Context, groupName, key string) bool {
	groupName = fmt.Sprintf("%v:%v", CacheValue, groupName)
	return operator.ExistValue(ctx, groupName, key)
}

// GetValue 获取值
func (r *Client) GetValue(ctx context.Context, groupName, key string, out interface{}) (err error) {
	groupName = fmt.Sprintf("%v:%v", CacheValue, groupName)
	return operator.GetValue(ctx, groupName, key, out)
}

// DelValue 删除值
func (r *Client) DelValue(ctx context.Context, groupName, key string) (err error) {
	groupName = fmt.Sprintf("%v:%v", CacheValue, groupName)
	return operator.DelValue(ctx, groupName, key)
}

// AddList 添加到列表
func (r *Client) AddList(ctx context.Context, listName string, value string) bool {
	listName = fmt.Sprintf("%v:%v", CacheList, listName)
	return operator.AddList(ctx, listName, value)
}

// BatchAddList 添加列表
func (r *Client) BatchAddList(ctx context.Context, listName string, value ...string) bool {
	listName = fmt.Sprintf("%v:%v", CacheList, listName)
	return operator.BatchAddList(ctx, listName, value...)
}

// DelList 删除列表数据
func (r *Client) DelList(ctx context.Context, listName string, value string) bool {
	listName = fmt.Sprintf("%v:%v", CacheList, listName)
	return operator.DelList(ctx, listName, value)
}

// PopFormList 获取列表中的第一个数据
func (r *Client) PopFormList(ctx context.Context, listName string) (value string) {
	listName = fmt.Sprintf("%v:%v", CacheList, listName)
	return operator.PopFormList(ctx, listName)
}

// BPopFormList 获取列表中的第一个数据
func (r *Client) BPopFormList(ctx context.Context, listName string) (value string) {
	listName = fmt.Sprintf("%v:%v", CacheList, listName)
	return operator.BPopFormList(ctx, listName)
}

// GetFirstFormList 获取列表中的第一个数据
func (r *Client) GetFirstFormList(ctx context.Context, listName string) (value string) {
	listName = fmt.Sprintf("%v:%v", CacheList, listName)
	return operator.GetFirstFormList(ctx, listName)
}

// GetItemFromList 获取元素
func (r *Client) GetItemFromList(ctx context.Context, listName string, item string) (value string) {
	listName = fmt.Sprintf("%v:%v", CacheList, listName)
	return operator.GetItemFromList(ctx, listName, item)
}

// GetRangeFromQueue 获取列表
func (r *Client) GetRangeFromQueue(ctx context.Context, listName string, count int64) []string {
	listName = fmt.Sprintf("%v:%v", CacheList, listName)
	return operator.GetRangeFromQueue(ctx, listName, count)
}

func (r *Client) ListRange(ctx context.Context, listName string, from, to int64) []string {
	listName = fmt.Sprintf("%v:%v", CacheList, listName)
	return operator.ListRange(ctx, listName, from, to)
}

// LenList 列表长度
func (r *Client) LenList(ctx context.Context, listName string) (length int64, err error) {
	listName = fmt.Sprintf("%v:%v", CacheList, listName)
	return operator.LenList(ctx, listName)
}

// AddListToTail 前插
func (r *Client) AddListToTail(ctx context.Context, listName string, value string) (err error) {
	listName = fmt.Sprintf("%v:%v", CacheList, listName)
	return operator.AddListToTail(ctx, listName, value)
}

// GetBit 获取bit
func (r *Client) GetBit(ctx context.Context, key string, offset int) (value int, err error) {
	key = fmt.Sprintf("%v:%v", CacheBit, key)
	return operator.GetBit(ctx, key, offset)
}

// SetBitWithExpireTime 设置bit
func (r *Client) SetBitWithExpireTime(ctx context.Context, key string, offset, value int, expiredTime time.Duration) (err error) {
	key = fmt.Sprintf("%v:%v", CacheBit, key)
	expire := expiredTime / time.Second
	return operator.SetBitWithExpireTime(ctx, key, offset, value, int64(expire))
}

// SetBit 设置bit
func (r *Client) SetBit(ctx context.Context, key string, offset, value int) (err error) {
	key = fmt.Sprintf("%v:%v", CacheBit, key)
	return operator.SetBit(ctx, key, offset, value)
}

// MGetBit 批量获取
func (r *Client) MGetBit(ctx context.Context, key string, offsets []int) (value []int, err error) {
	key = fmt.Sprintf("%v:%v", CacheBit, key)
	return operator.MGetBit(ctx, key, offsets)
}

// BatchDel 批量删除 完整key
func (r *Client) BatchDel(ctx context.Context, keys []string) (count int, err error) {
	return operator.BatchDel(ctx, keys)
}

// DeletedRedisItem 删除redis item 完整key
func (r *Client) DeletedRedisItem(ctx context.Context, cacheType CacheType, key string) bool {
	key = fmt.Sprintf("%v:%v", cacheMap[cacheType], key)
	return operator.DeletedRedisItem(ctx, key)
}

// Expire 设置过期时间 完整key
func (r *Client) Expire(ctx context.Context, cacheType CacheType, key string, expiredTime time.Duration) (err error) {
	key = fmt.Sprintf("%v:%v:%v", operator.PrefixName(), cacheMap[cacheType], key)
	expire := expiredTime / time.Second
	return operator.Expire(ctx, key, int32(expire))
}

// ExistsKey 是否存在
func (r *Client) ExistsKey(ctx context.Context, cacheType CacheType, groupName, key string) bool {
	groupName = fmt.Sprintf("%v:%v", cacheMap[cacheType], groupName)
	return operator.ExistsKey(ctx, groupName, key)
}

// MatchDel 模糊删除
func (r *Client) MatchDel(cacheType CacheType, prefixKey string) (err error) {
	prefixKey = fmt.Sprintf("%v:%v:%v", operator.PrefixName(), cacheMap[cacheType], prefixKey)
	return operator.MatchDel(r.GetRedisPool().Get(), prefixKey)
}

func (r *Client) MatchCount(cacheType CacheType, prefixKey string) (count int64, err error) {
	prefixKey = fmt.Sprintf("%v:%v:%v", operator.PrefixName(), cacheMap[cacheType], prefixKey)
	return operator.MatchCount(r.GetRedisPool().Get(), prefixKey)
}

// GetPrefixName prefix
func (r *Client) GetPrefixName(cacheType CacheType) string {
	return fmt.Sprintf("%v:%v", operator.PrefixName(), cacheMap[cacheType])
}

func (r *Client) GetRedisPool() *Redis.Pool {
	return operator.GetRedisClient().GetPool()
}
